﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Management;
using System.Runtime.Versioning;
using System.Text;
using UtilZ.Dotnet.Ex.Base;
using UtilZ.Dotnet.WindowsDesktopEx.Base;
using UtilZ.Dotnet.WindowsDesktopEx.NativeMethod;

namespace UtilZ.Tool.HostQuery
{
    [SupportedOSPlatform("windows")]
    internal class WindowsQuery : IOSQuery
    {
        private readonly static char[] _argsTrimChas = new char[] { '"', '\'', ' ' };

        public WindowsQuery()
        {

        }


        /// <summary>
        /// 查询进程参数
        /// </summary>
        /// <param name="pid">进程ID</param>
        /// <returns>查询结果</returns>
        public string QueryProcessStartArgs(int pid)
        {
            string commandLine = GetCommandLineArgs(pid);
            return SubArgs(commandLine);
        }

        private static string SubArgs(string commandLine)
        {
            if (string.IsNullOrEmpty(commandLine))
            {
                return null;
            }

            int subIndex = -1;
            bool isFind = false;
            if (commandLine.StartsWith('"'))
            {
                for (int i = 1; i < commandLine.Length; i++)
                {
                    if (isFind)
                    {
                        if (commandLine[i] != ' ')
                        {
                            subIndex = i;
                            break;
                        }
                    }
                    else
                    {
                        if (commandLine[i] == '"')
                        {
                            isFind = true;
                        }
                    }
                }
            }
            else
            {
                for (int i = 0; i < commandLine.Length; i++)
                {
                    if (isFind)
                    {
                        if (commandLine[i] != ' ')
                        {
                            subIndex = i;
                            break;
                        }
                    }
                    else
                    {
                        if (commandLine[i] == ' ')
                        {
                            isFind = true;
                        }
                    }
                }
            }

            if (subIndex > 0)
            {
                return commandLine.Substring(subIndex).Trim(_argsTrimChas);
            }
            else
            {
                return commandLine.Trim(_argsTrimChas);
            }
        }

        private static string GetCommandLineArgs(int pid)
        {
            try
            {
                using (var searcher = new ManagementObjectSearcher("SELECT CommandLine FROM Win32_Process WHERE ProcessId = " + pid))
                {
                    using (var objects = searcher.Get())
                    {
                        var @object = objects.Cast<ManagementBaseObject>().SingleOrDefault();
                        return @object?["CommandLine"]?.ToString() ?? "";
                    }
                }
            }
            catch (Win32Exception ex) when ((uint)ex.ErrorCode == 0x80004005)
            {
                // 没有对该进程的安全访问权限。
                return string.Empty;
            }
            catch (InvalidOperationException)
            {
                // 进程已退出。
                return string.Empty;
            }
        }



        /// <summary>
        /// 获取崩溃进程ID列表
        /// </summary>
        /// <returns></returns>
        public List<int> GetCrushProcessIdList()
        {
            //MainWindow (未响应)
            //return WindowHelper.FindWindows(t => { return t.Title != null && t.Title.EndsWith("(未响应)"); });
            IReadOnlyList<WindowInfo> windowInfoList = WindowHelper.FindWindows();
            if (windowInfoList == null || windowInfoList.Count == 0)
            {
                return null;
            }

            List<int> crushProcessIdList = this.GetCrushProcessIdListByCrushWindowTitle(windowInfoList, null);
            crushProcessIdList = this.GetCrushProcessIdListByCrushWindowSize(windowInfoList, crushProcessIdList);
            crushProcessIdList = this.GetCsrssCrushProcessIdList(crushProcessIdList);
            crushProcessIdList = this.GetWerfaultCrushProcessIdList(crushProcessIdList);
            crushProcessIdList = this.GetVsjitdebuggerCrushProcessIdList(crushProcessIdList);

            if (crushProcessIdList == null || crushProcessIdList.Count == 0)
            {
                return windowInfoList.Where(t =>
                {
                    return t.Title != null && t.Title.EndsWith("(未响应)") ||
                    t.Title.Contains("noResponse", StringComparison.OrdinalIgnoreCase);
                }).Select(p => { return p.ProcessId; }).ToList();
            }

            return crushProcessIdList;


            //Title = "MainWindow (未响应)"
            //string noResponceWindowTitle = $"{this._process.MainWindowTitle} (未响应)";
            //string noResponceWindowTitle = $"{this._process.MainWindowTitle}{WatchdogConfig.Instance.NoRespondingWindowTitleSuffix}";
            //WindowInfo noResponceWindow = windowInfoList.FirstOrDefault(t =>
            //{
            //    return t.Title.Contains(noResponceWindowTitle);
            //});
            //if (noResponceWindow != null)
            //{
            //    Loger.Info($"程序\"{this._appName}\"未响应重启");
            //    this.KillProcess();
            //    this.PrimitiveStart();
            //    return;
            //}

        }

        private List<int> GetCrushProcessIdListByCrushWindowSize(IReadOnlyList<WindowInfo> windowInfoList, List<int> crushProcessIdList)
        {
            List<CrushWindowSize> crushWindowSizeList = HostQueryConfig.Instance.CrushWindowSizeList;
            if (crushWindowSizeList == null || crushWindowSizeList.Count == 0)
            {
                return crushProcessIdList;
            }

            //+		Bounds	{X = 1165 Y = 607 Width = 451 Height = 332}	System.Drawing.Rectangle
            foreach (var crushWindowSize in crushWindowSizeList)
            {
                foreach (var windowInfo in windowInfoList)
                {
                    if (crushWindowSize.Width == windowInfo.Bounds.Width &&
                        crushWindowSize.Height == windowInfo.Bounds.Height)
                    {
                        if (crushProcessIdList == null)
                        {
                            crushProcessIdList = new List<int>();
                        }
                        else
                        {
                            if (crushProcessIdList.Contains(windowInfo.ProcessId))
                            {
                                continue;
                            }
                        }

                        crushProcessIdList.Add(windowInfo.ProcessId);
                    }
                }
            }

            return crushProcessIdList;
        }

        private List<int> GetCrushProcessIdListByCrushWindowTitle(IReadOnlyList<WindowInfo> windowInfoList, List<int> crushProcessIdList)
        {
            List<string> crushWindowTitles = HostQueryConfig.Instance.CrushWindowTitles;
            if (crushWindowTitles == null || crushWindowTitles.Count == 0)
            {
                return crushProcessIdList;
            }

            foreach (string crushWindowTitle in crushWindowTitles)
            {
                foreach (var windowInfo in windowInfoList)
                {
                    if (windowInfo.ProcessId <= 0)
                    {
                        continue;
                    }

                    if (windowInfo.Title.Contains(crushWindowTitle))
                    {
                        if (crushProcessIdList == null)
                        {
                            crushProcessIdList = new List<int>();
                        }
                        else
                        {
                            if (crushProcessIdList.Contains(windowInfo.ProcessId))
                            {
                                continue;
                            }
                        }

                        crushProcessIdList.Add(windowInfo.ProcessId);
                    }
                }
            }

            return crushProcessIdList;
        }


        private List<int> GetCsrssCrushProcessIdList(List<int> crushProcessIdList)
        {
            //List<int> crushProcessIdList = null;
            Process[] csrssProcessArr = Process.GetProcessesByName("csrss");//csrss.exe进程
            int colonIndex, minusIndex;
            string errProcessName;
            foreach (var csrssProcess in csrssProcessArr)
            {
                if (string.IsNullOrWhiteSpace(csrssProcess.MainWindowTitle))
                {
                    continue;
                }

                //csrssProcess.MainWindowTitle：excepiton_console.exe - 应用程序错误
                //csrssProcess.MainWindowTitle：MainWindow: exception_qt.exe - 应用程序错误

                minusIndex = csrssProcess.MainWindowTitle.LastIndexOf('-');
                if (minusIndex < 0)
                {
                    continue;
                }

                colonIndex = csrssProcess.MainWindowTitle.IndexOf(':');
                if (colonIndex > 0)
                {
                    errProcessName = Path.GetFileNameWithoutExtension(csrssProcess.MainWindowTitle.Substring(colonIndex + 1, minusIndex - colonIndex).Trim());
                }
                else
                {
                    errProcessName = Path.GetFileNameWithoutExtension(csrssProcess.MainWindowTitle.Substring(0, minusIndex).Trim());
                }

                var crushOriginProcessArr = Process.GetProcessesByName(errProcessName);
                if (crushOriginProcessArr.Length > 0)
                {
                    //if (crushProcessIdList == null)
                    //{
                    //    crushProcessIdList = new List<int>();
                    //}

                    //foreach (var crushOriginProcesse in crushOriginProcessArr)
                    //{
                    //    crushProcessIdList.Add(crushOriginProcesse.Id);
                    //}

                    csrssProcess.CloseMainWindow();//只需要关掉此窗口,该进程就自动结束,然后看门狗就自动重启
                }
            }

            return crushProcessIdList;
        }

        private List<int> GetVsjitdebuggerCrushProcessIdList(List<int> crushProcessIdList)
        {
            Process[] vsjitdebuggerProcessArr = Process.GetProcessesByName("vsjitdebugger");//vsjitdebugger.exe进程
            foreach (var vsjitdebuggerProcess in vsjitdebuggerProcessArr)
            {
                if (string.IsNullOrWhiteSpace(vsjitdebuggerProcess.MainWindowTitle))
                {
                    continue;
                }

                vsjitdebuggerProcess.CloseMainWindow();//只需要关掉此窗口,该进程就自动结束,然后看门狗就自动重启
            }

            return crushProcessIdList;
        }

        //仅支持windows桌面程序,控制台不支持,只能舍弃了
        private List<int> GetWerfaultCrushProcessIdList(List<int> crushProcessIdList)
        {
            //List<int> crushProcessIdList = null;
            Process[] werfaultProcessArr = Process.GetProcessesByName("werfault");//Werfault.exe进程
            foreach (var werfaultProcess in werfaultProcessArr)
            {
                var werfaultCheckProcessId = this.GetWerfaultProcessId(werfaultProcess.Id);
                werfaultProcess.Kill();
                werfaultProcess.Dispose();
                if (werfaultCheckProcessId <= 0 ||
                    crushProcessIdList != null && crushProcessIdList.Contains(werfaultCheckProcessId))
                {
                    continue;
                }

                if (crushProcessIdList == null)
                {
                    crushProcessIdList = new List<int>();
                }
                crushProcessIdList.Add(werfaultCheckProcessId);
            }

            return crushProcessIdList;
        }

        /// <summary>
        /// 获取进程命令行信息
        /// </summary>
        /// <param name="pId"></param>
        /// <returns></returns>
        private int GetWerfaultProcessId(int werfaultProcessId)
        {
            try
            {
                using (ManagementObjectSearcher search = new ManagementObjectSearcher($"select CommandLine from Win32_Process where ProcessId={werfaultProcessId}"))
                {
                    using (ManagementObjectCollection moc = search.Get())
                    {
                        object obj;
                        foreach (ManagementObject mo in moc)
                        {
                            //werfault.exe /h /shared Global\\409752f6ec4c49a7a9aaaf24be671079 /t 10084 /p 29732
                            obj = mo["CommandLine"];
                            if (obj == null)
                            {
                                continue;
                            }

                            string commandLine = obj.ToString();
                            if (string.IsNullOrWhiteSpace(commandLine))
                            {
                                continue;
                            }

                            const string PRO_PARA = "/p";
                            int index = commandLine.IndexOf(PRO_PARA);
                            if (index >= 0)
                            {
                                string pidStr = commandLine.Substring(index + PRO_PARA.Length).Trim();
                                index = pidStr.IndexOf(' ');
                                if (index > 0)
                                {
                                    pidStr = pidStr.Substring(0, index).Trim();
                                }

                                int pid;
                                if (int.TryParse(pidStr, out pid))
                                {
                                    return pid;
                                }
                            }
                            break;
                        }
                    }
                }
            }
            catch (ManagementException)
            { }
            catch (System.Runtime.InteropServices.COMException)
            { }

            return -1;
        }




        public bool IsNoResponse(IntPtr mainWindowHandle)
        {
            return WindowHelper.IsNoResponse(mainWindowHandle);
        }
    }
}
